package roborally.Pieces;

import java.util.Random;

import roborally.Board;
import roborally.util.MoveOutOfBoardException;
/**
 * This is a class of GamePieces representing surprise boxes that can do different
 * things when used.

 * @version 3.0
 * @author 	Bart Opsomer 2de Bachelor Ingenieurswetenschappen Electrotechniek-Computerwetenschappen 
 * 		   	Peter Opsomer 1ste Master Wiskundige IngenieursTechnieken
 */
public class SurpriseBox extends Item {
	
	/**
	 * Create a new SurpriseBox with the given weight in grams.
	 * @effect super(weight)
	 */
	public SurpriseBox(int weight) {
		super(weight);
	}
	/**
	 * Override the default use-method from Item.
	 * Randomly do 1 of the following : teleportRandom(robot) or explode(robot) or newItem(robot)
	 * @post	the surprisebox has been terminated and dropped by the robot
	 * 			| new.isTerminated() && !robot.getInventory().contains(this)
	 * @effect	randomly : teleportRandom(robot) or explode(robot) or newItem(robot)
	 * 			| teleportRandom(robot) || explode(robot) || newItem(robot)
	 */
	@Override
	public void use(Robot robot) {
		Random rand = new Random();
		switch (rand.nextInt(3)) {
		case 0:
			teleportRandom(robot);
			break;
		case 1:
			explode(robot);
			break;
		case 2:
			newItem(robot);
			break;
		}
		this.terminate();
		robot.drop(this);
	}
	/**
	 * Teleport the robot to a random position on the board.
	 * @param robot the robot to be teleported
	 * @post	the robot is teleported to a empty position on board
	 * 			| ! robot.getBoard.isisOccupiedPosition( (new robot).getPosition() )
	 * @effect	System.out.println("The surprisebox has teleported you,"+robot.getPosition().toString())
	 */
	private void teleportRandom(Robot robot) {
		Random random = new Random();
		PositionWithOrientation postionWithOrientation = robot.getPositionWithOrientation();
		long x,y;
		Board board = postionWithOrientation.getBoard();
		Orientation orientation = postionWithOrientation.getOrientation();
		PositionWithOrientation newPostionWithOrientation = null;
		
		// continue the loop as long as the robot is not teleported
		while(newPostionWithOrientation == null || postionWithOrientation.equals(newPostionWithOrientation)) {
			// random.nextDouble() generates a double in between 0 and 1 that multiplied by a number gives 
			// a random number in between 0 and the given number
			x = (long) (random.nextDouble()*(double)board.getWidth());
			y = (long) (random.nextDouble()*(double)board.getHeight());
			try {
				if(Position.isValidPosition(board, x, y)) {
					newPostionWithOrientation= PositionWithOrientation.getPWO(x, y, board, orientation);
					// check if the newPostionWithOrientation.getPosition() is an empty position on the board
					if(!board.isOccupiedPosition(newPostionWithOrientation.getPosition())) {
						// Also first remove Robot so that Board knows that previous location is not occupied by robot
						board.removeRobot(robot);
						board.addRobot(robot,newPostionWithOrientation);
					}
				}
			}
			catch (MoveOutOfBoardException exc) {
				// No Valid empty Position
			}
		}
		System.out.println("The surprisebox has teleported you to "+robot.getPosition().toString());
	}
	/**
	 * Explode: the effect of a explosion in the hands of a robot is the same for the robot as being shoot.
	 * The SurpriseBox is dropped by the calling method SurpriseBox.use, so it cannot explode again.
	 * @param robot the robot that uses this surprisebox
	 * @effect	the robot is hit and a message is generated
	 * 			| robot.shootThis() && System.out.println("The surprisebox has exploded")
	 */
	private void explode(Robot robot) {
		robot.shootThis();
		System.out.println("The surprisebox has exploded");
	}
	/**
	 * Add a new item to the robot's inventory, randomly.
	 * @param robot the robot to which inventory the random item is to be added
	 * @post	an item is added to the robots inventory
	 * 			| robot.getInventory().size() +1 = (new robot).getInventory().size()
	 */
	private void newItem(Robot robot) {
		Random random = new Random();
		Item item = null;
		switch (random.nextInt(3)) {
		case 0:
			item = new SurpriseBox(1500);
			System.out.println("A new Suprise box is added to the inventory");
			break;
		case 1:
			item = new RepairKit(new Energy(8000),1500);
			System.out.println("A new RepairKit is added to the inventory");
			break;
		case 2:
			item = new Battery();
			System.out.println("A new Battery is added to the inventory");
			break;
		}
		Board board = robot.getPosition().getBoard();
		board.addItem(robot.getPosition(), item);
		robot.pickupItem(item);
	}
	/**
	 * Overrides the default shootThis method of GamePiece.
	 * SupriseBox explodes and hits all neighboring fields
	 * @post 	all neighboring fields are hit by the explosion
	 * 			| foreach position where position.getManhattenDistance(this.getPosition()) = 1
	 * 			| 	this.getBoard().explosionAt(position)
	 */
	@Override
	public void shootThis() {
		Position positionOfSupriseBox = this.getPosition();
		Board board = positionOfSupriseBox.getBoard();
		PositionWithOrientation position;
		// No explosion at this Position: would get in an infinite loop
		for(Orientation orientation : Orientation.values()) {
			try {
				position = orientation.getNextPosition(positionOfSupriseBox);
				board.explosionAt(position.getPosition());
			}
			catch (MoveOutOfBoardException exc) {
				// Not a valid position, NOP
			}
		}
	}
	/**
	 * Return a textual representation of this Surprisebox for the GUI. This method gives information about the weight and then the position of the Surprisebox.
	 * 
	 * @return | result.equals("Surprisebox with 3 possibilities" + super.toString() )
	 */
	@Override
	public String toString() {
		return "Surprisebox with 3 possibilities"+ super.toString();
	}

}
